package com.ht.api.controller;

import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import com.ht.api.bean.AjaxResult;
import com.ht.api.bean.LoginBean;
import com.ht.api.bean.UserInfo;
import com.ht.api.call.ICall;
import com.ht.api.constant.CacheConstants;
import com.ht.api.db.Entity;
import com.ht.api.db.bean.DataResult;
import com.ht.api.db.bean.SessionBean;
import com.ht.api.db.exception.HtException;
import com.ht.api.db.request.HandleRequestUtil;
import com.ht.api.db.util.RedisUtil;
import com.ht.api.util.UserUtil;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;

/**
 * 通用接口
 * @author asq
 * @createTime 2024年12月23日 20:52:01
 */
@RestController
public class CallController {
	@Autowired
	private Map<String, ICall> callMap;

	/**
	 * 通用的调用接口（使用租户数据源）
	 * @param key 接口KEY
	 * @param body 接口参数
	 * @return
	 */
	@PostMapping("/call/{key}")
	public AjaxResult callByTenant(@PathVariable String key, @RequestBody(required = false) JSONObject body) {
		// 获取登录用户
		UserInfo loginUser = UserUtil.getLoginUser();
		long loginId = loginUser.getId();
		long tenantId = loginUser.getTenantId();
		LoginBean loginBean = LoginBean.createByTenant(loginId, tenantId);
		loginBean.setSysCommonCall(false);
		return call(loginBean, key, body);
	}

	/**
	 * 通用的调用接口（使用系统数据源）
	 * @param key 接口KEY
	 * @param body 接口参数
	 * @return
	 */
	@PostMapping("/call/sys/{key}")
	public AjaxResult callBySys(@PathVariable String key, @RequestBody(required = false) JSONObject body) {

		// 获取登录用户
		UserInfo loginUser = UserUtil.getLoginUser();
		long loginId = loginUser.getId();
		long tenantId = loginUser.getTenantId();
		LoginBean loginBean = LoginBean.createByTenant(loginId, tenantId);
		loginBean.setSysCommonCall(true);

		return call(loginBean, key, body);
	}
	
	/**
	 * 通用的调用接口，指定数据源
	 * @param me 操作人
	 * @param key 接口KEY
	 * @param body 接口参数
	 * @return
	 */
	private AjaxResult call(LoginBean me, String key, JSONObject body) {
		// 验证请求参数
		checkParam(body);

		// 获取key对应的call表对象
		Entity callEntity = getCallEntity(key);

		// 验证权限
		checkPerms(callEntity.getStr("perms"));
		
		// 根据call接口的type字段，判断是否是新接口，从而走不同的调用流程
		Integer callType = callEntity.getInt("type");
		if (callType != null && callType == 1) {// 新接口，按新流程调用
			SessionBean sessionMe = SessionBean.createByTenant(me.getTenantId());
			sessionMe.setSysCommonCall(me.isSysCommonCall());
	    	DataResult result = HandleRequestUtil.callFunc(sessionMe, key, body);
	    	if (StrUtil.isBlank(result.getMsg())) {
	    		return AjaxResult.success(result.getData());
	    	} else {
	    		return AjaxResult.success(result.getMsg(), result.getData());
	    	}
		} else {// 兼容老接口
			// 根据不同的type，获取具体接口
			JSONObject config = callEntity.getJSONObject("config");
			String type = config.getStr("type");
			ICall call = callMap.get(String.format("%sCall", type));
	
			// 调用具体接口
			return call.execute(me, body, config);
		}
	}

	/**
	 * 验证参数
	 * @param body 请求体参数
	 */
	private void checkParam(JSONObject body) {
		if (body == null) {
			throw new HtException("请求体不能为空~");
		}
		if (StrUtil.isBlankIfStr(body.getStr(ICall.PARAM))) {
			throw new HtException("参数param不能为空~");
		}
	}

	/**
	 * 验证当前登录用户是否有权限
	 * @param perms 权限字符串
	 */
	private void checkPerms(String perms) {
		if (StrUtil.isNotBlank(perms)) {
			UserInfo loginUser = UserUtil.getLoginUser();
			if (loginUser == null) {
				throw new HtException("未登录不允许访问本接口~");
			}

			if (!loginUser.isAdmin() && !loginUser.getPerms().contains(perms)) {
				throw new HtException(String.format("没有接口访问权限:%s", perms));
			}
		}
	}

	/**
	 * 从缓存中获取call表数据
	 * @param key call表数据对应的key值
	 * @return
	 */
	private Entity getCallEntity(String key) {
		Entity bean = RedisUtil.get(CacheConstants.KEY_CALL + key);
		if (bean == null || bean.isEmpty()) {
			throw new HtException("不正确的key参数~");
		}
		return bean;
	}

}
